home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Nebula 1
/
Nebula One.iso
/
Mail
/
pine3.92
/
pico
/
os_dos.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-03-14
|
14KB
|
619 lines
/*
* $Id: os_dos.c,v 4.38 1996/03/15 07:41:11 hubert Exp $
*
* Program: Operating system dependent routines - MS DOS
*
*
* Michael Seibel
* Networks and Distributed Computing
* Computing and Communications
* University of Washington
* Administration Builiding, AG-44
* Seattle, Washington, 98195, USA
* Internet: mikes@cac.washington.edu
*
* Please address all bugs and comments to "pine-bugs@cac.washington.edu"
*
*
* Pine and Pico are registered trademarks of the University of Washington.
* No commercial use of these trademarks may be made without prior written
* permission of the University of Washington.
*
* Pine, Pico, and Pilot software and its included text are Copyright
* 1989-1996 by the University of Washington.
*
* The full text of our legal notices is contained in the file called
* CPYRIGHT, included with this distribution.
*
*
* Notes:
* - mouse support added (mss, 921215)
*
* Portions of this code derived from MicroEMACS 3.10:
*
* MSDOS.C: Operating specific I/O and Spawning functions
* under the MS/PCDOS operating system
* for MicroEMACS 3.10
* (C)opyright 1988 by Daniel M. Lawrence
*
*/
#include <stdio.h>
#include <errno.h>
#include <setjmp.h>
#include <time.h>
#include <fcntl.h>
#include <io.h>
#include <bios.h>
#include "osdep.h"
#include "pico.h"
#include "estruct.h"
#include "edef.h"
#include "dos_gen.h"
/*
* Internal functions...
*/
int enhanced_keybrd(void);
int dont_interrupt(void);
int interrupt_ok(void);
int kbseq(int *);
int specialkey(unsigned int);
char *pfnexpand(char *, int);
int ssleep(long);
int sleep(int);
/*
* Useful global def's
*/
int timeout = 0;
static int enhncd = 0; /* keyboard of enhanced variety? */
union REGS rg;
struct SREGS segreg;
static int oldbut; /* Previous state of mouse buttons */
static unsigned short oldbreak; /* Original state of break key */
static char ptmpfile[128]; /* popen temp file */
/*
* Include generic DOS/Windows routines
*/
#include "dos_gen.c"
/*
* DISable ctrl-break interruption
*/
dont_interrupt()
{
/* get original value, to be restored later... */
rg.h.ah = 0x33; /* control-break check dos call */
rg.h.al = 0; /* get the current state */
rg.h.dl = 0; /* pre-set it OFF */
intdos(&rg, &rg); /* go for it! */
oldbreak = rg.h.dl;
/* kill the ctrl-break interupt */
rg.h.ah = 0x33; /* control-break check dos call */
rg.h.al = 1; /* set the current state */
rg.h.dl = 0; /* set it OFF */
intdos(&rg, &rg); /* go for it! */
}
/*
* re-enable ctrl-break interruption
*/
interrupt_ok()
{
/* restore the ctrl-break interupt */
rg.h.ah = 0x33; /* control-break check dos call */
rg.h.al = 1; /* set to new state */
rg.h.dl = oldbreak; /* set it to its original value */
intdos(&rg, &rg); /* go for it! */
}
/*
* return true if an enhanced keyboard is present
*/
enhanced_keybrd()
{
/* and check for extended keyboard */
rg.h.ah = 0x05;
rg.x.cx = 0xffff;
int86(BIOS_KEYBRD, &rg, &rg);
rg.h.ah = 0x10;
int86(BIOS_KEYBRD, &rg, &rg);
return(rg.x.ax == 0xffff);
}
/*
* This function is called once to set up the terminal device streams.
*/
ttopen()
{
dont_interrupt(); /* don't allow interrupt */
enhncd = enhanced_keybrd(); /* check for extra keys */
#if MOUSE
init_mouse();
#else /* !MOUSE */
mexist = 0;
#endif /* MOUSE */
return(1);
}
/*
* ttresize - recompute the screen dimensions if necessary, and then
* adjust pico's internal buffers accordingly
*/
int
ttresize ()
{
return (0); /* no op */
}
#ifdef MOUSE
/*
* init_mouse - check for and initialize mouse driver...
*/
init_mouse()
{
long miaddr; /* mouse interupt routine address */
if(mexist)
return(TRUE);
/* check if the mouse drive exists first */
rg.x.ax = 0x3533; /* look at the interrupt 33 address */
intdosx(&rg, &rg, &segreg);
miaddr = (((long)segreg.es) << 16) + (long)rg.x.bx;
if (miaddr == 0 || *(char *)miaddr == 0xcf) {
mexist = FALSE;
return(TRUE);
}
/* and then check for the mouse itself */
rg.x.ax = 0; /* mouse status flag */
int86(BIOS_MOUSE, &rg, &rg); /* check for the mouse interupt */
mexist = (rg.x.ax != 0);
nbuttons = rg.x.bx;
if (mexist == FALSE)
return(TRUE);
/* if the mouse exists.. get it in the upper right corner */
rg.x.ax = 4; /* set mouse cursor position */
rg.x.cx = (term.t_ncol/2) << 3; /* Center of display... */
rg.x.dx = 1 << 3; /* Second line down */
int86(BIOS_MOUSE, &rg, &rg);
/* and set its attributes */
rg.x.ax = 10; /* set text cursor */
rg.x.bx = 0; /* software text cursor please */
rg.x.cx = 0x77ff; /* screen mask */
rg.x.dx = 0x7700; /* cursor mask */
int86(BIOS_MOUSE, &rg, &rg);
return(TRUE);
}
/*
* mouseon - call made available for programs calling pico to turn ON the
* mouse cursor.
*/
void
mouseon()
{
rg.x.ax = 1; /* Show Cursor */
int86(BIOS_MOUSE, &rg, &rg);
}
/*
* mouseon - call made available for programs calling pico to turn OFF the
* mouse cursor.
*/
void
mouseoff()
{
rg.x.ax = 2; /* Hide Cursor */
int86(BIOS_MOUSE, &rg, &rg);
}
#endif
/*
* This function gets called just before we go back home to the command
* interpreter.
*/
ttclose()
{
if(!Pmaster)
interrupt_ok();
return(1);
}
/*
* Flush terminal buffer. Does real work where the terminal output is buffered
* up. A no-operation on systems where byte at a time terminal I/O is done.
*/
ttflush()
{
return(1);
}
/*
* specialkey - return special key definition
*/
specialkey(kc)
unsigned kc;
{
switch(kc){
case 0x3b00 : return(F1);
case 0x3c00 : return(F2);
case 0x3d00 : return(F3);
case 0x3e00 : return(F4);
case 0x3f00 : return(F5);
case 0x4000 : return(F6);
case 0x4100 : return(F7);
case 0x4200 : return(F8);
case 0x4300 : return(F9);
case 0x4400 : return(F10);
case 0x8500 : return(F11);
case 0x8600 : return(F12);
case 0x4800 : return(K_PAD_UP);
case 0x5000 : return(K_PAD_DOWN);
case 0x4b00 : return(K_PAD_LEFT);
case 0x4d00 : return(K_PAD_RIGHT);
case 0x4700 : return(K_PAD_HOME);
case 0x4f00 : return(K_PAD_END);
case 0x4900 : return(K_PAD_PREVPAGE);
case 0x5100 : return(K_PAD_NEXTPAGE);
case 0x5300 : return(K_PAD_DELETE);
case 0x48e0 : return(K_PAD_UP); /* grey key version */
case 0x50e0 : return(K_PAD_DOWN); /* grey key version */
case 0x4be0 : return(K_PAD_LEFT); /* grey key version */
case 0x4de0 : return(K_PAD_RIGHT); /* grey key version */
case 0x47e0 : return(K_PAD_HOME); /* grey key version */
case 0x4fe0 : return(K_PAD_END); /* grey key version */
case 0x49e0 : return(K_PAD_PREVPAGE); /* grey key version */
case 0x51e0 : return(K_PAD_NEXTPAGE); /* grey key version */
case 0x53e0 : return(K_PAD_DELETE); /* grey key version */
default : return(NODATA);
}
}
/*
* Read a character from the terminal, performing no editing and doing no echo
* at all. Also mouse events are forced into the input stream here.
*/
ttgetc()
{
return(_bios_keybrd(enhncd ? _NKEYBRD_READ : _KEYBRD_READ));
}
/*
* ctrlkey - used to check if the key hit was a control key.
*/
ctrlkey()
{
return(_bios_keybrd(enhncd ? _NKEYBRD_SHIFTSTATUS : _KEYBRD_SHIFTSTATUS)
& 0x04);
}
/*
* win_multiplex - give DOS in a window a shot at the CPU
*/
win_multiplex()
{
rg.x.ax = 0x1680;
int86(DOS_MULTIPLEX, &rg, &rg);
}
/*
* Read in a key.
* Do the standard keyboard preprocessing. Convert the keys to the internal
* character set. Resolves escape sequences and returns no-op if global
* timeout value exceeded.
*/
GetKey()
{
unsigned ch = 0, lch, intrupt = 0;
long timein;
if(mexist || timeout){
timein = time(0L);
#ifdef MOUSE
if(mexist){
rg.x.ax = 1; /* Show Cursor */
int86(BIOS_MOUSE, &rg, &rg);
}
#endif
while(!_bios_keybrd(enhncd ? _NKEYBRD_READY : _KEYBRD_READY)){
#if MOUSE
if(timeout && time(0L) >= timein+timeout){
if(mexist){
rg.x.ax = 2; /* Hide Cursor */
int86(BIOS_MOUSE, &rg, &rg);
}
return(NODATA);
}
if(checkmouse(&ch,0,0,0)){ /* something happen ?? */
if(mexist){
rg.x.ax = 2; /* Hide Cursor */
int86(BIOS_MOUSE, &rg, &rg);
}
curwp->w_flag |= WFHARD;
return(ch);
}
#else
if(time(0L) >= timein+timeout)
return(NODATA);
#endif /* MOUSE */
/*
* Surrender the CPU...
*/
if(!intrupt++)
win_multiplex();
}
#ifdef MOUSE
if(mexist){
rg.x.ax = 2; /* Hide Cursor */
int86(BIOS_MOUSE, &rg, &rg);
}
#endif /* MOUSE */
}
ch = (*term.t_getchar)();
lch = (ch&0xff);
return((lch && (lch != 0xe0 || !(ch & 0xff00)))
? (lch < ' ') ? (CTRL|(lch + '@'))
: (lch == ' ' && ctrlkey()) ? (CTRL|'@') : lch
: specialkey(ch));
}
#if MOUSE
/*
* checkmouse - look for mouse events in key menu and return
* appropriate value.
* NOTE: "down", "xxx", and "yyy" aren't used under DOS.
*/
int
checkmouse(ch, down, xxx, yyy)
unsigned *ch;
int down, xxx, yyy;
{
register int k; /* current bit/button of mouse */
int mcol; /* current mouse column */
int mrow; /* current mouse row */
int sstate; /* current shift key status */
int newbut; /* new state of the mouse buttons */
int button;
int rv = 0;
if(!mexist)
return(FALSE);
/* check to see if any mouse buttons are different */
rg.x.ax = 3; /* Get button status and mouse position */
int86(BIOS_MOUSE, &rg, &rg);
newbut = rg.x.bx;
mcol = rg.x.cx >> 3;
mrow = (rg.x.dx >> 3);
/* only notice changes */
if (oldbut == newbut)
return(FALSE);
if (mcol < 0) /* only on screen presses are legit! */
mcol = 0;
if (mrow < 0)
mrow = 0;
sstate = 0; /* get the shift key status as well */
rg.h.ah = 2;
int86(BIOS_KEYBRD, &rg, &rg);
sstate = rg.h.al;
button = M_BUTTON_LEFT;
for (k=1; k != (1 << nbuttons); k = k<<1) {
/* For each button on the mouse */
if ((oldbut&k) != (newbut&k)) {
if(k == 1){
static int oindex;
int i = 0;
MENUITEM *mp;
if(newbut&k) /* button down */
oindex = -1;
for(mp = mfunc; mp; mp = mp->next)
if(mp->action && M_ACTIVE(mrow, mcol, mp))
break;
if(mp){
unsigned long r;
r = (*mp->action)((newbut&k) ? M_EVENT_DOWN : M_EVENT_UP,
mrow, mcol, button, 0);
if(r & 0xffff){
*ch = (unsigned)((r>>16)&0xffff);
rv = TRUE;
}
}
else{
while(1){ /* see if we understand event */
if(i >= 12){
i = -1;
break;
}
if(M_ACTIVE(mrow, mcol, &menuitems[i]))
break;
i++;
}
if(newbut&k){ /* button down */
oindex = i; /* remember where */
if(i != -1) /* invert label */
invert_label(1, &menuitems[i]);
}
else{ /* button up */
if(oindex != -1){
if(i == oindex){
*ch = menuitems[i].val;
rv = 1;
}
}
}
}
if(!(newbut&k) && oindex != -1)
invert_label(0, &menuitems[oindex]); /* restore label */
}
oldbut = newbut;
return(rv);
}
++button;
}
return(FALSE);
}
/*
* invert_label - highlight the label of the given menu item.
*/
void
invert_label(state, m)
int state;
MENUITEM *m;
{
int i, j, r, c, p, col_offset;
char *lp;
int old_state = getrevstate();
if(m->val == mnoop)
return;
rg.h.ah = 3; /* get cursor position */
int86(BIOS_VIDEO, &rg, &rg);
p = rg.h.bh;
c = rg.h.dl;
r = rg.h.dh;
rg.x.ax = 2; /* Hide Cursor */
int86(BIOS_MOUSE, &rg, &rg);
/*
* Leave the command name bold
*/
col_offset = (state || !(lp=strchr(m->label, ' '))) ? 0 : (lp - m->label);
(*term.t_move)(m->tl.r, m->tl.c + col_offset);
(*term.t_rev)(state);
for(i = m->tl.r; i <= m->br.r; i++)
for(j = m->tl.c + col_offset; j <= m->br.c; j++)
if(i == m->lbl.r && j == m->lbl.c + col_offset){ /* show label?? */
lp = m->label + col_offset;
while(*lp && j++ < m->br.c)
(*term.t_putchar)(*lp++);
continue;
}
else
(*term.t_putchar)(' ');
(*term.t_rev)(old_state);
rg.h.ah = 2;
rg.h.bh = p;
rg.h.dh = r;
rg.h.dl = c;
int86(BIOS_VIDEO, &rg, &rg); /* restore old position */
rg.x.ax = 1; /* Show Cursor */
int86(BIOS_MOUSE, &rg, &rg);
}
#endif /* MOUSE */
/*
* alt_editor - fork off an alternate editor for mail message composition
*
* NOTE: Not yet used under DOS
*/
alt_editor(f, n)
{
return(-1);
}
/*
* bktoshell - suspend and wait to be woken up
*/
bktoshell() /* suspend MicroEMACS and wait to wake up */
{
int i;
char *shell;
(*term.t_move)(term.t_nrow, 0);
if(system((shell = getenv("COMSPEC")) ? shell : "command") == -1)
emlwrite("Error loading %s", shell ? shell : "COMMAND.COM");
else
refresh(0, 1); /* redraw */
}
/*
* P_open - run the given command in a sub-shell returning a file pointer
* from which to read the output
*
* note:
* For OS's other than unix, you will have to rewrite this function.
* Hopefully it'll be easy to exec the command into a temporary file,
* and return a file pointer to that opened file or something.
*/
FILE *P_open(c)
char *c;
{
char cmdbuf[NLINE];
sprintf(ptmpfile, tmpnam(NULL));
sprintf(cmdbuf, "%s > %s", c, ptmpfile);
if(system(cmdbuf) == -1){
unlink(ptmpfile);
return(NULL);
}
return(fopen(ptmpfile, "r"));
}
/*
* P_close - close the given descriptor
*
*/
P_close(fp)
FILE *fp;
{
fclose(fp); /* doesn't handle return codes */
unlink(ptmpfile);
return(0);;
}